function NW03_yc_wj(jd, zsxx, dizih) {
    this.jd = jd;
    this.wjDX = jd.files[0];            // js 获取文件对象

    this.cs_cc = 0;                 // 文件尺寸
    this.cs_jzwhz = true;    //  禁止无后缀的文件 -3
    this.cs_wjhz_hmd = [];   //  文件后缀 黑名单1 阻止
    this.cs_lx_hmd = [];     //  文件类型 黑名单2 阻止
    this.cs_wjhz_bmd = [];   //  文件后缀 白名单  通过
    this.cs_lx_bmd = [];     //  文件类型 白名单  通过

    this.jd_zsxx = zsxx;                // 展示上传信息（过程、结束）的节点
    this.dizih = dizih;                 // 接收上传文件的后台地址
    this.xhr = new XMLHttpRequest();    // XMLHttpRequest 对象
    this.xhr['_wo_sfz'] = this;

    this.sycSJ; //上一次时间
    this.ljZJ;  //累计字节。已经上传了多少字节数据
    this.ff;    //上传结果。用户设置。成功或失败，都会调用这个函数。
    this.zt = null;

    this.hk_shuju = null;//后台返回的文本。
    //成功与失败的代号：比如，数据库返回  {dh:0,cg:'上传失败',dizhi:''}  {dh:1,cg:'上传成功',dizhi:'上传路径...'}
    this.hk_dh = 'dh';

}


NW03_yc_wj.prototype.xsxx = function (xx) {
    if (this.jd_zsxx) {
        this.jd_zsxx.innerHTML = xx;
    }
}


// 0=M 1=kb 2=原始不变。
NW03_yc_wj.prototype.wjcc = function (cc, lx) {
    if (lx == 0 || lx == undefined) {
        this.cs_cc = cc * 1024 * 1024;
        return;
    }
    if (lx == 1) {
        this.cs_cc = cc * 1024
        return;
    }
    this.cs_cc = cc;
}

//  文件类型 黑名单
NW03_yc_wj.prototype.hmd_lx = function (cs) {
    return this._ngj_zhi('cs_lx_hmd', cs)
}
//  文件后缀 黑名单
NW03_yc_wj.prototype.hmd_hz = function (cs) {
    return this._ngj_zhi('cs_wjhz_hmd', cs)
}
//  文件类型 白名单
NW03_yc_wj.prototype.bmd_lx = function (cs) {
    return this._ngj_zhi('cs_lx_bmd', cs)
}
//  文件后缀 白名单
NW03_yc_wj.prototype.bmd_hz = function (cs) {
    return this._ngj_zhi('cs_wjhz_bmd', cs)
}

NW03_yc_wj.prototype._ngj_zhi = function (sx, zhi) {
    if (zhi == undefined) {
        return this[sx];
    }
    if (zhi.indexOf(',')) {
        zhi = zhi.split(',');
        for (let i = 0; i < zhi.length; i++) {
            this[sx].push(zhi[i]);
        }
    } else {
        this[sx].push(zhi);
    }
    return this;
}


NW03_yc_wj.prototype.zbCS = function () {
    //黑名单
    for (let i = 0; i < this.cs_lx_hmd.length; i++) {
        this.cs_lx_hmd[i] = this.hqWJLX(this.cs_lx_hmd[i]);
    }
    //白名单
    for (let i = 0; i < this.cs_lx_bmd.length; i++) {
        this.cs_lx_bmd[i] = this.hqWJLX(this.cs_lx_bmd[i]);
    }
}

NW03_yc_wj.prototype.hqWJLX = function (dh) {
    switch (dh) {
        case 'exe': return 'application/x-msdownload';
        case 'pdf': return 'application/pdf';
        case 'txt': return 'text/plain';
        case 'tar.gz': return 'application/x-gzip';
        case 'zip': return 'application/x-zip-compressed';
        case 'pdf': return ' ';
        case 'jpeg': return 'image/jpeg';
        case 'jpeg': return 'image/png'
        case 'docx': return 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
        case 'doc': return 'application/msword';
        case 'xls': return 'application/vnd.ms-excel';
        case 'xlsx': return 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';

    }
}


NW03_yc_wj.prototype.zxff = function (dh) {
    if (this.ff) {
        this.ff(dh, this)
    }
}


//停止
NW03_yc_wj.prototype.tz = function () {
    this.xhr.abort();
}

//0）如果配置了文件最大值，先检查文件尺寸。不符合，即可阻止
//1）只要在黑名单，即可阻止。
//2）在白名单，ok
//3）不在黑名单，也不在白单名（如果 白名单 非空），同样阻止。
//4) 没有配置黑名单、白名单。直接通过。 

//true=校验出错，不通过; false=校验通过
NW03_yc_wj.prototype.cw = function () {
    if (!this.wjDX) {
        this.zxff(-2);
        this.xsxx('【请选择文件】')
        return true;
    }
    //0）如果配置了文件最大值，先检查文件尺寸。不符合，即可阻止
    //比如，文件20M > 我配置了10M，阻止上传
    if (this.cs_cc > 0 && this.wjDX.size > this.cs_cc) {
        // console.log('超出文件尺寸范围。' + this.cs_cc + '   文件=' + this.wjDX.size)
        this.zxff(-3);
        this.xsxx('超出文件尺寸范围:' + ((this.wjDX.size - this.cs_cc) / 1024 / 1024).toFixed(3) + 'M')
        return true;
    }
    //1）只要在黑名单，即可阻止。
    //黑名单 
    if (this._ngj_pdZhi('cs_lx_hmd', this.wjDX.type)) {
        this.xsxx('【文件类型】在 黑单名里面')
        this.zxff(-3);
        return true;
    }

    let mz = this.wjDX.name;
    let hz = mz.lastIndexOf('.') == -1 ? null : mz.substring(mz.lastIndexOf('.') + 1);
    if (!hz && this.cs_jzwhz) {//文件没有后缀，又禁止没有后缀的文件上传,则，禁止上传
        return true;
    }

    //黑名单 如果存在后缀
    if (this._ngj_pdZhi('cs_wjhz_hmd', hz)) {
        this.xsxx('【文件后缀】（' + hz + '） 在 黑名单里面')
        this.zxff(-3);
        return true;
    }
    //2）在白名单，ok
    //白名单 
    if (this._ngj_pdZhi('cs_lx_bmd', this.wjDX.type)) {
        // console.log('在 【类型白单名】里面。通过')
        return false;
    }

    //白名单 
    if (this._ngj_pdZhi('cs_wjhz_bmd', hz)) {
        // console.log('在 【后缀白单名】里面。通过')
        return false;
    }

    //3）不在黑名单，也不在白单名（如果 白名单 非空），同样阻止。
    if (this.cs_wjhz_bmd.length > 0 || this.cs_lx_bmd.length > 0) {
        // console.log('已经配置了白名单，但此文件不在 【不在白名单】 里面，阻止')
        this.xsxx('文件不在 【白名单】 里面')
        this.zxff(-3);
        return true;//阻止
    }
    //4) 没有配置黑名单、白名单。直接通过。 
    return false;
}

NW03_yc_wj.prototype._ngj_pdZhi = function (sx, zhi) {
    let sz = this[sx];
    for (let i = 0; i < sz.length; i++) {
        if (sz[i] == zhi) {
            return true;
        }
    }
    return false;
}



//上传方法
NW03_yc_wj.prototype.qd0 = function (ff, tb) {
    let wo = this;
    if (ff) {
        this.ff = ff;
    }
    // console.log('----------------------------------')
    this.zbCS()
    if (this.cw()) {
        return;
    }

    this.xhr.open("post", this.dizih, tb ? tb : true);  //post方式，url为服务器请求地址，true 该参数规定请求是否异步处理。

    this.xhr.onload = this._sqjg_cg;                    //请求完成
    this.xhr.onerror = this._sqjg_sb;                   //请求失败

    this.xhr.upload['_wo_sfz'] = this;

    this.bdDX = new FormData();                         // FormData 对象
    this.bdDX.append("file", this.wjDX);                // 文件对象
    this.xhr.upload.onprogress = this._scgc;            //【上传进度调用方法实现】
    this.xhr.upload.onloadstart = function () {         //上传开始执行方法
        wo.zt = null;
        wo.sycSJ = new Date().getTime();                //记录上传时间-开始
        wo.ljZJ = 0;                                    //设置上传开始时，以上传的文件大小为0
        wo.hk_shuju = null;
    };
    this.xhr.send(this.bdDX); //开始上传，发送form数据
}

//上传过程
NW03_yc_wj.prototype._scgc = function (e) {
    // let wo = nw.ff.yc.hqWJ(jd);
    let wo = e.currentTarget._wo_sfz;
    if (!wo.jd_zsxx) {
        return;
    }
    let hkxx = ''
    // e.total是需要传输的总字节，
    // e.loaded是已经传输的字节。
    // e.lengthComputable 不为真，则 e.total 等于0
    if (e.lengthComputable) {
        hkxx = Math.round(e.loaded / e.total * 100) + "%，";
    }
    let pertime = (new Date().getTime() - wo.sycSJ) / 1000; //计算出上次调用该方法时到现在的时间差，单位为s
    wo.sycSJ = new Date().getTime();        //重新赋值时间，用于下次计算
    let zlZJ = e.loaded - wo.ljZJ;          //针对累计的上传字节，现在，所【增量字节】
    wo.ljZJ = e.loaded;                     //重新赋值已上传文件大小，用以下次计算
    //上传速度计算
    let _sd = zlZJ / pertime;//单位b/s
    let _sd2 = _sd;
    let _dw = 'b/s';//单位名称
    if (_sd / 1024 > 1) {
        _sd = _sd / 1024;
        _dw = 'k/s';
    }
    if (_sd / 1024 > 1) {
        _sd = _sd / 1024;
        _dw = 'M/s';
    }
    _sd = _sd.toFixed(1);

    if (wo.ljZJ == 0) {
        wo.jd_zsxx.innerHTML = '无法上传'
    } else {
        wo.jd_zsxx.innerHTML = hkxx + '速度：' + _sd + _dw + '，剩余时间：' + (((e.total - e.loaded) / _sd2).toFixed(1)) + '秒';
    }
    if (_sd2 == 0) {
        wo.jd_zsxx.innerHTML = '上传已取消';
    }
}

NW03_yc_wj.prototype._sqjg_sb = function (e) {
    let wo = e.currentTarget._wo_sfz;
    wo.zt = 0;
    if (!e.target.responseText) {
        wo.zt = -1;
        wo.xsxx('<<<<<上传异常>>>>>')
    } else {
        wo.xsxx('<<<<<上传失败>>>>>')
    }

    wo.zxff(wo.zt);
}

//上传结果
NW03_yc_wj.prototype._sqjg_cg = function (e) {
    let wo = e.currentTarget._wo_sfz;
    let mb = e.target
    if (!mb.responseText) {
        wo.xsxx('<<<<<上传异常>>>>>')
        wo.zt = -1;
    } else {
        wo.hk_shuju = JSON.parse(mb.responseText);
        if (wo.hk_shuju && wo.hk_shuju[wo.hk_dh]) {
            wo.xsxx('上传成功')
            wo.zt = 1;
        } else {
            wo.zt = 0;
            wo.xsxx('<<<<<上传失败>>>>>')
        }
    }
    wo.zxff(wo.zt);
}